#include "GL/GLTexture.h"
#include "Logger.h"
#include "Exception.h"

NS_B2D_BEGIN


/// Utility structure for binding a texure for edit
/// It retrieves the bound texture and resets it one
/// the object goes out of scope (ie, editing has finished)
struct TempEditBind
{
	bool restore;
	GLint tmpName;
	TempEditBind(GLuint texName)
		: restore(false)
	{
		glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpName);
		if( tmpName != texName )
		{
			glBindTexture(GL_TEXTURE_2D, texName);
			restore = true;
		}
	}
	~TempEditBind(void)
	{
		if( restore )
			glBindTexture(GL_TEXTURE_2D, tmpName);
	}
};

//
// GLTexture
//

B2D_OBJECT_IMPL(GLTexture, Texture)

GLTexture::GLTexture(void)
	: mTextureHandle(0)
{
	glGenTextures(1, &mTextureHandle);
	if( mTextureHandle != 0 )
	{
		B2D_LOG_DEBUG("Texture \"%s\" was initialised\n", mName.getString().c_str());
	}
	else
	{
		B2D_THROW(Exception::GRAPHICS_API_EXCEPTION,
			"Failed to create texture: \"" + mName.getString() +"\".");
	}
}

GLTexture::~GLTexture(void)
{
	glDeleteTextures(1, &mTextureHandle);
	mTextureHandle = 0;
	B2D_LOG_DEBUG("Texture \"%s\" was released\n", mName.getString().c_str());
}

void GLTexture::initialiseWithDataImpl(const void* data)
{
	const int mipmapLevel = 0;

	GLenum format;
	GLint internalFormat;
	GLenum type;
	GLGraphicEnumConverter::getTextureFormat(mTextureFormat, format, internalFormat, type);
		
	// Generate GL texture temporarily
	TempEditBind tempBind(mTextureHandle);
	// Set data
	glTexImage2D(GL_TEXTURE_2D,
		mipmapLevel,
		internalFormat,
		mWidth,
		mHeight,
		mBorder, 
		format,
		type,
		data);
	// TODO SP - check this succeded?
		
	// Generate mipmaps
	if(mHasMipmaps == true)
	{
		if( glGenerateMipmap != nullptr )
			glGenerateMipmap(GL_TEXTURE_2D);
		else if( glGenerateMipmapEXT != nullptr )
			glGenerateMipmapEXT(GL_TEXTURE_2D);
		else
		{
			// TODO SP - glGenerateMipmaps not in GL2.1?
			// need to revise mipmap generation, maybe manual?
			B2D_LOG_ERROR("Mipmaps for the texture \"%s\" could not be generated.", mName.getString().c_str());
			// B2D_THROW(Exception::NOT_SUPPORTED_EXCEPTION, "");
		}
	}

	
	B2D_LOG_DEBUG("New pixel data set to texture \"%s\"\n", mName.getString().c_str());
}
/*
void GLTexture::updateSamplerStateImpl(void)
{
	TempEditBind tempBind(mTextureHandle);
	GLenum minFilter, magFilter;
	if( mHasMipmaps )
	{
		minFilter = GLGraphicEnumConverter::getTextureMipmapFilter(mSamplerState.minFilter, mSamplerState.mipFilter);
		magFilter = GLGraphicEnumConverter::getTextureMipmapFilter(mSamplerState.magFilter, mSamplerState.mipFilter);
	}
	else
	{
		minFilter = GLGraphicEnumConverter::getTextureFilter(mSamplerState.minFilter);
		magFilter = GLGraphicEnumConverter::getTextureFilter(mSamplerState.magFilter);
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
}*/

NS_B2D_END